#include "TabelMK.h"
#include "..\cgraphics\cgraphics.h"

// KONSTRUKTOR - DESTRUKTOR
TabelMK		CreateEmptyTabelMK() {
	TabelMK T = NULL;
	return T;
}

AddressMK	AllocateRecordMK(string KodeMK, string NamaMK, int SKS, string Bidang) {
	AllocateRecordMKAdv(KodeMK,NamaMK,SKS,Bidang,NULL);
}

AddressMK	AllocateRecordMKAdv(string KodeMK, string NamaMK, int SKS, string Bidang, AddressMK next) {
	AddressMK M = (AddressMK) malloc(sizeof(RecordMK));
	if(M!=NULL) {
		KODEMK(M) 	= KodeMK;
		NAMA_MK(M) 	= NamaMK;
		SKS(M) 		= SKS;
		BIDANG(M)	= Bidang;
		NEXT(M) 	= next;
		OWNERLIST(M)= NULL;
	}
	return M;
}

void 		DeallocateRecordMK(RecordMK *MK) {
	free(MK);
}

// PREDIKAT
bool		IsRecordMKEqual(AddressMK A, AddressMK B) {
	return IsStringEqual(KODEMK(A),KODEMK(B));
}

// OPERASI
void		ChangeRecordMKContent(AddressMK MK, string kodebaru, string Namabaru, int SKSBaru, string bidangBaru) {
	KODEMK(MK) 	= kodebaru;
	NAMA_MK(MK) = Namabaru;
	SKS(MK) 	= SKSBaru;
	BIDANG(MK)	= bidangBaru;
}

int 		GetRecordMKSize(AddressMK MK) {
	return KODEMK(MK).length + NAMA_MK(MK).length + BIDANG(MK).length + 2;
}

void	 	AddRecordMK(AddressMK MK, TabelMK *TMK) {
	if(ISLINKEDLISTEMPTY(*TMK)) { // Jika kosong
		FIRST(*TMK) = MK;
		NEXT(MK) = NULL;
	}
	else if(IsStringLt(NAMA_MK(MK),NAMA_MK(FIRST(*TMK)))) { // Jika elmt pertama > MK
		NEXT(MK) = FIRST(*TMK);
		FIRST(*TMK) = MK;
	}
	else {
		AddressMK M;
		TRAVERSETOEND(M,FIRST(*TMK)) 
			if(IsStringLt(NAMA_MK(MK),NAMA_MK(NEXT(M)))) break;
		
		NEXT(MK) = NEXT(M);
		NEXT(M) = MK;
	}
}

void	 	DestroyRecordMK(AddressMK MK, TabelMK *TMK) {
	if(MK==FIRST(*TMK)) {
		FIRST(*TMK) = NEXT(MK);
	}
	else {
		AddressMK M;
		TRAVERSETOEND(M,FIRST(*TMK))
			if(NEXT(M)==MK) break;
		
		NEXT(M) = NEXT(NEXT(M));
	}
	DeallocateRecordMK(MK);
}
	
AddressMK	SearchRecordMKByKode(string KodeMK, TabelMK *TMK) {
	AddressMK retval;
	if(ISLINKEDLISTEMPTY(*TMK)) { // Jika kosong
		retval = NULL;
	}
	else if(IsStringEqual(KodeMK,KODEMK(FIRST(*TMK)))) { // Jika elmt pertama memiliki NIM
		retval = FIRST(*TMK);
	}
	else {
		AddressMK M;
		TRAVERSETOEND(M,FIRST(*TMK)) 
			if(IsStringEqual(KodeMK,KODEMK(NEXT(M)))) break;
		
		retval = NEXT(M);
	}
	return retval;
}
		
AddressMK	SearchRecordMK(AddressMK MK, TabelMK *TMK) {
	AddressMK retval;
	if(ISLINKEDLISTEMPTY(*TMK)) { // Jika kosong
		retval =  NULL;
	}
	else if(MK == FIRST(*TMK)) { // Jika elmt pertama sama
		retval = FIRST(*TMK);
	}
	else {
		AddressMK M;
		TRAVERSETOEND(M,FIRST(*TMK)) 
			if(MK == NEXT(M)) break;
		
		retval = NEXT(M);
	}
	return retval;
}
	
void		AddOwnerToRecordMK(AddressMK MK, ownerAddress O) {
	AddOwner(&OWNERLIST(MK),O);
}

bool 		EvaluateQueryTabelMKPhase2(AddressMK MK, Reader R, string compare, bool *query_succeed) {
	Reader temp = R;
	bool retval;
	*query_succeed = true;
	if(IsStringEqual(temp.argument[0],Kol_KodeMK)) {
		if(IsStringEqual(compare,CharToString("<"))) {
			retval = IsStringLt(KODEMK(MK),temp.argument[2]);
		}
		else {
			retval = IsStringEqual(KODEMK(MK), temp.argument[2]);
		}
	}
	else if(IsStringEqual(temp.argument[0],Kol_NamaMK)) {
		if(IsStringEqual(compare,CharToString("<"))) {
			retval = IsStringLt(NAMA_MK(MK),temp.argument[2]);
		}
		else {
			retval = IsStringEqual(NAMA_MK(MK), temp.argument[2]);
		}
	}
	else if(IsStringEqual(temp.argument[0],Kol_Bidang)) {
		if(IsStringEqual(compare,CharToString("<"))) {
			retval = IsStringLt(BIDANG(MK),temp.argument[2]);
		}
		else {
			retval = IsStringEqual(BIDANG(MK), temp.argument[2]);
		}
	}
	else if(IsStringEqual(temp.argument[0],Kol_SKS)) {
		if(!IsStringFloat(temp.argument[2])){
			StartPrintMsg(); printf("QUERY ERROR : %s bukan angka\n",temp.argument[2].s);
			*query_succeed = false;
		}
		else {
			if(IsStringEqual(compare,CharToString("<"))) {
				retval = (SKS(MK) < StringToInt(temp.argument[2]));
			}
			else {
				retval = (SKS(MK) == StringToInt(temp.argument[2]));
			}
		}
	}
	else {
		*query_succeed = false;
		StartPrintMsg(); printf("QUERY ERROR : Kolom tidak terdefinisi!\n");
		retval = false;
	}
	return retval;
}

bool 		EvaluateQueryTabelMK(AddressMK MK, Reader R, bool *query_succeed) {
	// exit jika argument < 3
	if(R.nArgument < 3) {
		StartPrintMsg(); printf("QUERY ERROR : Query tidak lengkap\n");
		*query_succeed = false;
		return false;
	}
	
	*query_succeed = true;

	Reader temp = R;
	bool retval;
	if(IsStringEqual(temp.argument[1],CharToString("<"))) {
		retval = EvaluateQueryTabelMKPhase2(MK, R, temp.argument[1], query_succeed);
	}
	else if(IsStringEqual(temp.argument[1],CharToString("<="))) {
		retval = EvaluateQueryTabelMKPhase2(MK, R, CharToString("<"), query_succeed) || EvaluateQueryTabelMKPhase2(MK, R, CharToString("="), query_succeed);
	}
	else if(IsStringEqual(temp.argument[1],CharToString(">="))) {
		retval = !EvaluateQueryTabelMKPhase2(MK, R, CharToString("<"), query_succeed);
	}
	else if(IsStringEqual(temp.argument[1],CharToString(">"))) {
		retval = !EvaluateQueryTabelMKPhase2(MK, R, CharToString("<"), query_succeed) && !EvaluateQueryTabelMKPhase2(MK, R, CharToString("="), query_succeed);
	}
	else if(IsStringEqual(temp.argument[1],CharToString("=="))) {
		retval = EvaluateQueryTabelMKPhase2(MK, R, CharToString("="), query_succeed);
	}
	else if(IsStringEqual(temp.argument[1],CharToString("!="))) {
		retval = !EvaluateQueryTabelMKPhase2(MK, R, CharToString("="), query_succeed);
	}
	else {
		StartPrintMsg(); printf("QUERY ERROR : Perintah relasional %s tidak dikenali!\n", temp.argument[1].s);
		retval = false;
		*query_succeed = false;
	}
	
	
	if(R.nArgument==3) { // basis  
		return retval;
	}
	else if(IsStringEqual(temp.argument[3],CharToString("AND"))) { // rekursi
		DeleteArguments(&temp,0,4);
		return retval && EvaluateQueryTabelMK(MK, temp, query_succeed);
	}
	else if(IsStringEqual(temp.argument[3],CharToString("OR"))) { // rekursi
		DeleteArguments(&temp,0,4);
		return retval || EvaluateQueryTabelMK(MK, temp, query_succeed);
	}
	else {
		StartPrintMsg();printf("QUERY ERROR : Perintah relasional %s tidak dikenali!\n", temp.argument[3].s);
		*query_succeed = false;
		return false;
	}
}
	
int 		CountRecordMK(TabelMK T) {
	int c = 0;
	AddressMK M;
	TRAVERSETOEND2(M,FIRST(T)) c++;
	return c;
}

int			CountNodeRecordMK(TabelMK T, nodeAddress N) {
	int c = 0;
	AddressMK M;
	TRAVERSETOEND2(M,FIRST(T)) 
		if(SearchOwnerByNode(&OWNERLIST(M),N)) c++;
		
	return c;
}

void		DestroyTabelMK(TabelMK *T) {
	AddressMK M;
	TRAVERSETOEND2(M, FIRST(*T)) {
		DestroyRecordMK(M, &(*T));
	}
	*T = NULL;
}

// OUTPUT - for testing
void		PrintTabelMK(TabelMK T) {
	if(ISLINKEDLISTEMPTY(T)) {
		puts("-EMPTY-");
	}
	else {
		PrintTabelMKHeader(true,true,true,true); puts("");
		AddressMK M;
		TRAVERSETOEND(M,FIRST(T)) {
			PrintRecordMK(M,true,true,true,true); puts("");
		}
		PrintRecordMK(M,true,true,true,true); puts("");
	}
}

void		PrintTabelMKHeader(bool showKode, bool showNama, bool showSKS, bool showBidang) {
	if(showKode) {
		string s = Kol_KodeMK;
		printf("%-10s", s.s);
	}
	if(showNama) {
		string s = Kol_NamaMK;
		printf("%-40s", s.s);
	}
	if(showSKS) {
		string s = Kol_SKS;
		printf("%-5s", s.s);
	}
	if(showBidang) {
		string s = Kol_Bidang;
		printf("%-15s", s.s);
	}
}
	
void		PrintRecordMK(AddressMK MK, bool showKode, bool showNama, bool showSKS, bool showBidang) {
	if(showKode) printf("%-10s", KODEMK(MK).s);
	if(showNama) printf("%-40s", NAMA_MK(MK).s);
	if(showSKS) printf("%-5d", SKS(MK));
	if(showBidang) printf("%-15s", BIDANG(MK).s);
}
	
